package com.yeskery.nut.util;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

/**
 * multipart/form-data 工具类
 * @author YESKERY
 * 2024/8/14
 */
public class FormDataUtils {
    /** 字符池 */
    private static final String CHAR_POOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    /** 字符池大小 */
    private static final int POOL_SIZE = CHAR_POOL.length();
    /** 随机数生成器 */
    private static final SecureRandom RANDOM = new SecureRandom();

    /**
     * 私有化构造方法
     */
    private FormDataUtils() {
    }

    /**
     * 创建表单字节数组
     * @param items 表单项集合
     * @return 表单字节数组
     */
    public static FormData createFormData(List<FormDataItem> items) {
        if (items == null || items.isEmpty()) {
            throw new IllegalArgumentException("FormData Item List Must Not Be Empty.");
        }
        FormData formData = new FormData();
        String serialNumber = generateFromDataRandomSerialNumber();
        String boundary = "----NutKitFormBoundary" + serialNumber;
        formData.boundary = boundary;
        List<byte[]> bytesList = new ArrayList<>(items.size());
        for (int i = 0; i < items.size(); i++) {
            FormDataItem item = items.get(i);
            StringBuilder sb = new StringBuilder();
            if (i > 0) {
                sb.append("\r\n");
            }
            sb.append("--").append(boundary).append("\r\n");
            sb.append("Content-Disposition: form-data; name=\"").append(item.name).append("\"");
            if (item.fileName != null) {
                sb.append("; filename=\"").append(item.fileName).append("\"");
            }
            sb.append("\r\n");
            if (item.contentType != null) {
                sb.append("Content-Type: ").append(item.contentType).append("\r\n");
            }
            sb.append("\r\n");
            byte[] bytes = sb.toString().getBytes();
            byte[] wholeBytes = new byte[bytes.length + item.data.length];
            System.arraycopy(bytes, 0, wholeBytes, 0, bytes.length);
            System.arraycopy(item.data, 0, wholeBytes, bytes.length, item.data.length);
            bytesList.add(wholeBytes);
        }
        bytesList.add(("\r\n--" + boundary + "--\r\n").getBytes());
        byte[] bytes = new byte[bytesList.stream().mapToInt(b -> b.length).sum()];
        int index = 0;
        for (byte[] value : bytesList) {
            System.arraycopy(value, 0, bytes, index, value.length);
            index += value.length;
        }
        formData.bytes = bytes;
        return formData;
    }

    /**
     * 创建普通表单项
     * @param name 名称
     * @param bytes 内容字节数组
     * @return 普通表单项
     */
    public static FormDataItem createNormalFormDataItem(String name, byte[] bytes) {
        FormDataItem item = new FormDataItem();
        item.name = name;
        item.data = bytes;
        return item;
    }

    /**
     * 创建文件表单项
     * @param name 名称
     * @param fileName 文件名
     * @param contentType 媒体类型
     * @param bytes 内容字节数组
     * @return 文件表单项
     */
    public static FormDataItem createFileFormDataItem(String name, String fileName, String contentType, byte[] bytes) {
        FormDataItem item = new FormDataItem();
        item.name = name;
        item.fileName = fileName;
        item.contentType = contentType;
        item.data = bytes;
        return item;
    }

    /**
     * 生成表单随机序列号
     * @return 表单随机序列号
     */
    private static String generateFromDataRandomSerialNumber() {
        StringBuilder sb = new StringBuilder(20);
        for (int i = 0; i < 20; i++) {
            sb.append(CHAR_POOL.charAt(RANDOM.nextInt(POOL_SIZE)));
        }
        return sb.toString();
    }

    /**
     * multipart/form-data 项
     * @author YESKERY
     * 2024/8/14
     */
    public static class FormDataItem {
        /** 名称 */
        private String name;
        /** 文件名 */
        private String fileName;
        /** 媒体类型 */
        private String contentType;
        /** 内容字节数组 */
        private byte[] data;
    }

    /**
     * multipart/form-data 对象
     * @author YESKERY
     * 2024/8/14
     */
    public static class FormData {
        /** 边界符 */
        private String boundary;

        /** 表单字节数组 */
        private byte[] bytes;

        /**
         * 获取边界符
         * @return 边界符
         */
        public String getBoundary() {
            return boundary;
        }

        /**
         * 获取表单字节数组
         * @return 表单字节数组
         */
        public byte[] getBytes() {
            return bytes;
        }
    }
}
